////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-2017 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camximagebuffer.h
///
/// @brief Image Buffer definition
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef CAMXIMAGEBUFFER_H
#define CAMXIMAGEBUFFER_H

#include "camxtypes.h"
#include "camxformats.h"
#include "camxcsl.h"
#include "camximagebuffermanager.h"

CAMX_NAMESPACE_BEGIN

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Forward Declarations
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class  ImageBufferManager;
class  ImageBuffer;
struct NativeHandle;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Representation of an image buffer including planes and format definitions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ImageBuffer
{
public:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ImageBuffer
    ///
    /// @brief  Constructor. Newly created image buffer will not contain any valid memory.
    ///
    /// @param  pImageBufferManager   Buffer manager that allocated the buffer (optional parameter which should be set
    ///                               to NULL if no buffer manager is required to be specified)
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    explicit ImageBuffer(
        ImageBufferManager* pImageBufferManager);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ~ImageBuffer
    ///
    /// @brief  Destructor. Will release any memory allocated. Buffers are not valid after the destructor is called.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ~ImageBuffer();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Allocate
    ///
    /// @brief  Allocate memory for the image buffer of the given format.
    ///
    /// @param  pStr                  The string tag indicates who is calling Allocate.
    /// @param  pFormat               The format of the buffer to allocate.
    /// @param  flags                 Usage flags for the memory to be allocated for this image buffer.
    /// @param  pDeviceIndices        List of device indices that may access this buffer.
    /// @param  deviceCount           The number of device indices pointed to by pDeviceIndices.
    /// @param  numBatchedFrames      Number of frames batched together
    ///
    /// @return CamxResultSuccess if successful.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult Allocate(
        const CHAR*           pStr,
        const ImageFormat*    pFormat,
        UINT32                flags,
        const INT32*          pDeviceIndices,
        UINT                  deviceCount,
        UINT                  numBatchedFrames);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Import
    ///
    /// @brief  Import previously allocated memory to be used with this memory buffer.
    ///
    /// @param  pFormat         The format of the buffer to import.
    /// @param  phNativeBuffer  The native handle of the buffer to import.
    /// @param  offset          Offset relative to the memory described by fd.
    /// @param  size            Size of the memory described by FD.
    /// @param  flags           Usage flags for the memory to be mapped for this image buffer.
    /// @param  pDeviceIndices  List of device indices that may access this buffer.
    /// @param  deviceCount     The number of device indices pointed to by pDeviceIndices.
    ///
    /// @return CamxResultSuccess if successful. If the previously allocated memory is not able to contain an image described
    ///         by pFormat, CamxResultEResource will be returned.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult Import(
        const ImageFormat*  pFormat,
        const NativeHandle* phNativeBuffer,
        SIZE_T              offset,
        SIZE_T              size,
        UINT32              flags,
        const INT32*        pDeviceIndices,
        UINT                deviceCount);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Release
    ///
    /// @brief  Release any allocated memory for this device and all references to underlying memory.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID Release();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// AddImageReference
    ///
    /// @brief  Add a reference to this image buffer. Only ImageBufferManager should call this API
    ///         as buffers are all managed through buffer manager.
    ///
    /// @return The updated reference count.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT AddImageReference();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ReleaseImageReference
    ///
    /// @brief  Release a reference to this image buffer. Only ImageBufferManager should call this API
    ///         as buffers are all managed through buffer manager.
    ///
    /// @return The updated reference count.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT ReleaseImageReference();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// AddBufferManagerImageReference
    ///
    /// @brief  Add a reference to this image buffer via ImageBufferManager.
    ///
    /// @return The updated reference count.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT AddBufferManagerImageReference();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ReleaseBufferManagerImageReference
    ///
    /// @brief  Release a reference to this image buffer via ImageBufferManager.
    ///
    /// @return The updated reference count.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT ReleaseBufferManagerImageReference();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetReferenceCount
    ///
    /// @brief  Get the current reference count.
    ///
    /// @return The reference count.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT GetReferenceCount();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetFormat
    ///
    /// @brief  Get the format of the buffer
    ///
    /// @return The image format. Will return NULL if the image buffer is not populated.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    const ImageFormat* GetFormat() const;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetNumberOfPlanes
    ///
    /// @brief  Get the number of planes for the buffer
    ///
    /// @return The number of planes.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT GetNumberOfPlanes() const;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPlaneSize
    ///
    /// @brief  Get the size of a plane in the buffer in bytes.
    ///
    /// @param  planeIndex  The plane to get.
    ///
    /// @return The number of bytes in the plane. Will return 0 if the image buffer is not populated.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    SIZE_T GetPlaneSize(
        UINT planeIndex
        ) const;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetFileDescriptor
    ///
    /// @brief  Get the fileDescriptor for the image.
    ///
    /// @return File Descriptor.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    INT GetFileDescriptor() const;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetNativeBufferHandle
    ///
    /// @brief  Get the native buffer handle for the image.
    ///
    /// @return The handle to the native buffer.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID* GetNativeBufferHandle() const;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPlaneVirtualAddr
    ///
    /// @brief  Get the virtual address of a plane in the image buffer.
    ///
    /// @param  batchFrameIndex If the imagebuffer is batched, then we set this to the frame index within the batch
    /// @param  planeIndex      The plane to get.
    ///
    /// @return The virtual address for the plane. Will return NULL if the image buffer is not populated or the buffer is not
    ///         mapped into the UMD.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BYTE* GetPlaneVirtualAddr(
        UINT batchFrameIndex,
        UINT planeIndex
        ) const;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPlaneCSLMemHandle
    ///
    /// @brief  Get the CSL Buffer information for a plane in the image buffer.
    ///
    /// @param  batchFrameIndex If the imagebuffer is batched, then we set this to the frame index within the batch
    /// @param  planeIndex      The plane to get.
    /// @param  phMemHandle     CSL memory handle out parameter.
    /// @param  pOffset         Output parameter. Offset of plane within the memory referred to by phMemHandle.
    /// @param  pMetadataSize   Output parameter. Metadatasize of the plane. For linear format Meta Size would be 0.
    ///
    /// @return CamxResultSuccess if successful.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetPlaneCSLMemHandle(
        UINT            batchFrameIndex,
        UINT            planeIndex,
        CSLMemHandle*   phMemHandle,
        SIZE_T*         pOffset,
        SIZE_T*         pMetadataSize
        ) const;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HasBackingBuffer
    ///
    /// @brief  Check whether the Image buffer is valid, having been backed by memory.
    ///
    /// @return TRUE if the ImageBuffer is valid and backed by memory, FALSE otherwise.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL HasBackingBuffer() const
    {
        return m_isBacked;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetNumFramesInBatch
    ///
    /// @brief  Retrieve the total frame numbers in one batch
    ///
    /// @return Return the number of frames in one batch
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT GetNumFramesInBatch() const
    {
        return m_numBatchedFrames;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CacheOps
    ///
    /// @brief  Clean and/or invalidate the cache for all memory associated with this image buffer.
    ///
    /// @param  invalidate  Invalidate the cache.
    /// @param  clean       Clean the cache.
    ///
    /// @return CamxResultSuccess if successful.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult CacheOps(
        BOOL invalidate,
        BOOL clean);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCPUAddress
    ///
    /// @brief  Retrieve the base virtual address for the image buffer
    ///
    /// @return Const byte pointer
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE const BYTE* GetCPUAddress() const
    {
        return m_pVirtualAddr;
    }

private:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ImportCSLBuffer
    ///
    /// @brief  Back this image buffer with a CSLBuffer.
    ///
    /// @param  pFormat     The format of the buffer to import.
    /// @param  pBufferInfo The CSL buffer information.
    ///
    /// @return CamxResultSuccess if successful.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult ImportCSLBuffer(
        const ImageFormat* pFormat,
        const CSLBufferInfo* pBufferInfo);

    ImageBuffer(const ImageBuffer& other)            = delete;
    ImageBuffer& operator=(const ImageBuffer& other) = delete;

    BOOL                  m_isBacked;                           ///< Track if the Image buffer is valid, having been
                                                                ///< backed by memory.
    UINT                  m_numBatchedFrames;                   ///< Batch size of the allocated buffer.
    CSLMemHandle          m_hBuffer;                            ///< CSL buffer backing the image buffer.
    SIZE_T                m_planeSize[FormatsMaxPlanes];        ///< Per plane size.
    SIZE_T                m_planeStartOffset[FormatsMaxPlanes]; ///< Per plane start offset in the allocated buffer.
    SIZE_T                m_metadataSize[FormatsMaxPlanes];     ///< Metadata Size
    BYTE*                 m_pVirtualAddr;                       ///< Starting virtual address of the allocated buffer.
    INT                   m_fileDescriptor;                     ///< The file descriptor of the buffer. If no valid file
                                                                ///< descriptor is available for the buffer, the fd is set to 0
    ImageFormat           m_format;                             ///< The buffer format.
    volatile UINT         m_aReferenceCount;                    ///< The reference count.
    ImageBufferManager*   m_pImageBufferManager;                ///< Buffer manager that allocated this buffer
    const NativeHandle*   m_phNativeBuffer;                     ///< Handle to the imported native buffer
};

CAMX_NAMESPACE_END

#endif // CAMXIMAGEBUFFER_H
